//! 验证服务模块
//! 提供MAC验证和PIN验证功能

use hex;
use log::{debug, error, warn};
use iso8583_rs::iso8583::iso_spec::IsoMsg;
use iso8583_rs::iso8583::IsoError;
use iso8583_rs::crypto::pin::verify_pin;
use iso8583_rs::crypto::pin::PinFormat::ISO0;
use iso8583_rs::crypto::mac::MacAlgo::RetailMac;
use iso8583_rs::crypto::mac::PaddingType::Type1;
use iso8583_rs::crypto::mac::verify_mac;
use crate::config::field_numbers;

/// MAC验证结果
#[derive(Debug, PartialEq)]
pub enum MacValidationResult {
    Valid,
    Invalid,
    NotPresent,
}

/// PIN验证结果
#[derive(Debug, PartialEq)]
pub enum PinValidationResult {
    Valid,
    Invalid,
    ProcessingError,
    NotPresent,
}

/// 验证服务
pub struct ValidationService {
    key: Vec<u8>,
}

impl ValidationService {
    /// 创建新的验证服务实例
    pub fn new(key: Vec<u8>) -> Self {
        Self { key }
    }

    /// 验证MAC
    pub fn validate_mac(&self, iso_msg: &IsoMsg, raw_msg: &[u8]) -> MacValidationResult {
        // 检查是否存在MAC字段
        if !iso_msg.bmp.is_on(field_numbers::MAC_PRIMARY as u32) && !iso_msg.bmp.is_on(field_numbers::MAC_SECONDARY as u32) {
            return MacValidationResult::NotPresent;
        }

        let field_num = if iso_msg.bmp.is_on(field_numbers::MAC_PRIMARY as u32) {
            field_numbers::MAC_PRIMARY.to_string()
        } else {
            field_numbers::MAC_SECONDARY.to_string()
        };

        match iso_msg.get_field_value(&field_num) {
            Ok(mac_str) => {
                let mac_data = &raw_msg[0..raw_msg.len() - 8];
                match hex::decode(mac_str) {
                    Ok(expected_mac_bytes) => {
                        match verify_mac(&RetailMac, &Type1, mac_data, &self.key, &expected_mac_bytes) {
                            Ok(_) => {
                                debug!("MAC验证成功");
                                MacValidationResult::Valid
                            }
                            Err(e) => {
                                error!("MAC验证失败: {}", e.msg);
                                MacValidationResult::Invalid
                            }
                        }
                    }
                    Err(_) => {
                        error!("MAC格式错误");
                        MacValidationResult::Invalid
                    }
                }
            }
            Err(_) => MacValidationResult::Invalid,
        }
    }

    /// 验证PIN
    pub fn validate_pin(&self, iso_msg: &IsoMsg, pin: &str) -> PinValidationResult {
        if !iso_msg.bmp.is_on(field_numbers::PIN_DATA as u32) {
            return PinValidationResult::NotPresent;
        }

        let f52 = match iso_msg.get_field_value(&field_numbers::PIN_DATA.to_string()) {
            Ok(pin_data) => pin_data,
            Err(_) => return PinValidationResult::ProcessingError,
        };

        let pan = match iso_msg.get_field_value(&field_numbers::PAN.to_string()) {
            Ok(pan_value) => pan_value,
            Err(_) => {
                error!("缺少PAN字段，无法验证PIN");
                return PinValidationResult::ProcessingError;
            }
        };

        debug!("开始验证PIN...");
        
        match hex::decode(f52) {
            Ok(pin_data_bytes) => {
                match verify_pin(&ISO0, pin, &pin_data_bytes, &pan, &self.key) {
                    Ok(is_valid) => {
                        if is_valid {
                            debug!("PIN验证成功");
                            PinValidationResult::Valid
                        } else {
                            warn!("PIN验证失败");
                            PinValidationResult::Invalid
                        }
                    }
                    Err(e) => {
                        error!("PIN验证处理错误: {}", e.msg);
                        PinValidationResult::ProcessingError
                    }
                }
            }
            Err(_) => {
                error!("PIN数据格式错误");
                PinValidationResult::ProcessingError
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use hex_literal::hex as hex_l;

    #[test]
    fn test_validation_service_creation() {
        let key = hex_l!("e0f4543f3e2a2c5ffc7e5e5a222e3e4d").to_vec();
        let service = ValidationService::new(key.clone());
        assert_eq!(service.key, key);
    }
}